前四章我们其实是从 curl 故事的"半路"切进去的——它早已有了 IP、早已知道要连 443。这一章补上故事的开头和结尾:从你的笔记本插上网线 / 连上 Wi-Fi,到一个网页真正显示出来,中间这几个应用层协议接力跑完了全程。我们按时间顺序走一遍:DHCP 拿地址 → DNS 查 IP → TLS 加密 → HTTP 取数据。
应用层(Application Layer):协议栈最顶层,直接服务于程序。这一章挑四个你天天在用、却很少看清的协议:DHCP、DNS、TLS、HTTP。
1DHCP:开机怎么拿到 IP
回忆 0.3:一台机器要上网,得有 IP、子网掩码(才能算同网段)、默认网关(才能出网段),还得知道 DNS 服务器地址。这些值哪来的?绝大多数情况下,是 DHCP(Dynamic Host Configuration Protocol)自动发的——它让一台刚联网、什么都不知道的机器,一次性拿全这些配置。过程四步,业内叫 DORA:
这像分布式系统里的服务发现:一个新节点上线,先广播找"注册中心",拿到配置再开始干活。DHCP 就是局域网版的服务发现 + 配置下发,只不过靠的是二层广播(0.2 那个 ff:ff:ff:ff:ff:ff)。
你家路由器最重要的身份之一,就是这台 DHCP 服务器。它手里攥着一个地址池(比如 192.168.1.100–.200),谁来就分一个、记下租约。OFFER 里那个"网关 .1、DNS .1"的 .1,通常就是路由器自己。OpenWRT 里这活儿由 dnsmasq(或 IPv6 的 odhcpd)干,配置在 /etc/config/dhcp——2.3 会专门拆。
看 DHCP 实际给了你什么(地址、网关、DNS、租期):
ipconfig getpacket en0 # macOS:打印完整 DHCP 应答
nmcli device show | grep -i dhcp # Linux(NetworkManager)
networkctl status # Linux(systemd-networkd)
2DNS:从域名到 IP
有了 IP,你想访问 example.com,可网络层只认 IP。把域名翻译成 IP,靠 DNS(Domain Name System)。回到 0.2 那个类比:ARP 把 IP→MAC,DNS 把域名→IP——都是"解析 + 缓存"。区别在于,DNS 的解析是分布式、分层的,不是广播一嗓子那么简单。第一次查 www.example.com(缓存全空)的解析链:
- 你的机器问本地 DNS(就是 DHCP 给你的那个,走 UDP 53 端口——这正是 0.4 说的"DNS 用 UDP");
- 本地 DNS 若没缓存,就代你递归查询:先问根服务器"com 归谁管?"→ 答"问 .com 的 TLD 服务器";
- 再问 .com TLD 服务器"example.com 归谁管?"→ 答"问 example.com 的权威服务器";
- 最后问权威服务器"www.example.com 的 IP?"→ 答
93.184.216.34; - 本地 DNS 把结果按 TTL 缓存,再返回给你。
根只知道"谁管 .com",.com 只知道"谁管 example.com",层层下问,每一级只掌握指向下一级的指针——和文件系统从根 inode 沿路径一级级走到目标 inode 是同一种结构。而且你几乎从不走完整条链:本地 DNS、操作系统、浏览器层层有缓存(按 TTL 过期)。这也是改了 DNS 记录要等一会儿才生效的原因。
你家路由器通常也兼任你的本地 DNS(DHCP 把 DNS 指向它自己)。dnsmasq 在上面做 DNS 缓存和转发:本地有记录(比如给内网设备起的名字)就直接答,没有就转发给上游(ISP 或 8.8.8.8 / 1.1.1.1)。正因为所有查询都过它的手,才能在路由器上做"DNS 分流""广告屏蔽"——2.7 会展开。
亲手跟踪整条解析链:
dig +trace www.example.com # 从根开始一步步问,能看到 root → TLD → 权威
dig example.com # 直接查,看最终结果和 TTL
nslookup example.com # 各平台通用
3TLS:在 TCP 之上加密
拿到 IP 后,客户端先和服务器做 TCP 三次握手(0.4)。连接通了,如果是 https,还要再握一次手:TLS(Transport Layer Security)握手,协商出密钥,把之后的 HTTP 数据全程加密。顺序务必分清:TCP 握手 → TLS 握手 → 加密通道里发 HTTP。https 的那个 s,就是这层。
TLS 握手(以现代 TLS 1.3 为例,简化)主要干两件事:
- 协商算法:双方商定用哪套加密套件(cipher suite);
- 认证 + 换密钥:服务器出示证书(certificate)证明"我确实是 example.com"(证书由 CA 签发,而你的系统信任这些 CA);双方借非对称加密,安全地协商出一把对称密钥。之后所有数据用这把对称密钥加密。
非对称加密(公钥 / 私钥)安全但慢,对称加密快但需要双方先共享同一把钥匙。TLS 的做法是:用慢而安全的非对称加密,只为安全地交换那把对称密钥;之后改用快的对称加密传数据。这套"非对称换钥 + 对称传输"的混合思路,你在 SSH 等很多安全协议里都会再遇到。
浏览器那个"小锁"和证书警告,验的就是握手里的证书:是不是可信 CA 签的、域名对不对、过没过期。你 702 里做 MITM 拦截 HTTPS,核心难点正在这里——必须先让客户端"信任"你伪造的证书(给设备装一个你自己的根 CA),否则 TLS 握手在证书验证那一步就直接失败,根本看不到明文。
看 TLS 协商过程和服务器证书:
# 看握手里协商的 TLS 版本、套件、证书主体
curl -v https://example.com 2>&1 | grep -E 'SSL|TLS|subject|issuer'
# 直接拉证书,看签发者(issuer)和有效期
openssl s_client -connect example.com:443 -servername example.com /dev/null \
| openssl x509 -noout -subject -issuer -dates
4HTTP:请求与响应
到这一步,前面全是铺垫——HTTP(HyperText Transfer Protocol)本身朴素得很:在(加密的)连接上,客户端发一段请求,服务器回一段响应,都是纯文本。请求 = 一行请求行 + 一堆头 + 可选 body:
GET / HTTP/1.1
Host: example.com
User-Agent: curl/8.0
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1256
<!doctype html>...
方法(GET / POST…)、状态码(200 / 404 / 500)、头(headers)——这些你做 TreasureDex 的 Express 后端天天在写。0.1 里 curl 拼的那段文本,就是这个请求。
HTTP 是无状态(stateless)的请求-响应:每个请求自带全部上下文,服务器不记得你上一条说了啥。这正是要靠 cookie / token 来"续上"会话的原因。你写 Express 路由处理 req / res,就工作在这一层。顺带一提:HTTP/1.1 是纯文本,HTTP/2 把它二进制化、多路复用,HTTP/3 干脆搬到 UDP 上的 QUIC(0.4 提过)——语义没变,传输方式在进化。
注意一个分层的结果:你家路由器工作在网络层 / 传输层,它看得到你连了哪个 IP 的 443 端口,却看不到 TLS 加密后的 HTTP 内容——那是客户端到服务器端到端加密的。这就是为什么路由器(以及中间任何转发设备)能记录"你访问了哪个站",却读不到你具体看了什么。分层 + 加密,把"转发"和"内容"干净地隔开了。
看完整的 HTTP 请求与响应头:
curl -v https://example.com 2>&1 | grep -E '^[<>]' # > 是发出的头,< 是收到的头
curl -sI https://example.com # 只看响应头
本章小结
- 从联网到加载网页,应用层四棒接力:DHCP(拿 IP / 网关 / DNS)→ DNS(域名→IP)→ TLS(加密)→ HTTP(请求响应)。
- DHCP 四步 DORA;服务器通常就是你家路由器(还顺手把网关和 DNS 都指向自己)。
- DNS 是分布式分层解析(根 → TLD → 权威),处处有缓存(按 TTL);走 UDP 53。
- TLS 在 TCP 之上握手,用"非对称换钥 + 对称传输"的混合加密;证书验身份(702 MITM 的命门)。
- HTTP 无状态请求-响应;HTTP/2 二进制、HTTP/3 搬到 QUIC。
- 路由器在 L3/L4 转发:看得到你连的 IP:443,看不到 TLS 加密后的内容。
动手练习
- 跑
dig +trace www.example.com,把"根 → .com → 权威"这条链在输出里逐级找出来,对照本章的解析链。 - macOS 跑
ipconfig getpacket en0(或 Linux 看 DHCP 信息),找出 DHCP 给你的网关和 DNS 地址——它俩是不是同一个(你家路由器)? - 思考题:第二次访问同一个网站明显更快。结合本章,列出至少两处"缓存 / 复用"在起作用(提示:DNS 缓存、TLS 会话复用、连接复用……)。
- 进阶:用
openssl s_client -connect example.com:443看证书的 issuer(签发它的 CA),再想想 702 里 MITM 为什么必须先让客户端信任一个你自己的 CA,才能拦下 HTTPS 明文。